package com.wei;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.wei.model.Coordinate;
import com.wei.model.Extent;
import com.wei.model.MapConfig;
import com.wei.model.Size;
import com.wei.model.TileCoord;

public class BaiduSourceProvider {

	private BaiduTileGrid tileGrid = null;
	private String url = "http://online%d.map.bdimg.com/onlinelabel/?qt=tile&styles=pl&udt=20171026&scaler=1&p=1&qt=tile&x={x}&y={y}&z={z}";
	private int offsetZoom = 0;
	private int curIndex = 0;
	private int curZoomIdx = 0;

	public BaiduSourceProvider(MapConfig config) {
		if(config == null) {
			return ;
		}
		Size tileSize = new Size(config.getTileSize()[0], config.getTileSize()[1]);
		Extent extent = new Extent(config.getExtent());
		Coordinate origin = new Coordinate(config.getOrigin());

		tileGrid = new BaiduTileGrid(config.getResolutions(), extent, origin, tileSize);
		offsetZoom = config.getOffsetZoom();
		curIndex = config.getIndex();
		curZoomIdx = config.getZoom();
	}

	public BaiduTileGrid getTmsTileGrid() {
		return this.tileGrid;
	}
	
	public int getCurIndex() {
		return this.curIndex;
	}
	
	public void setCurIndex(int index) {
		this.curIndex = index;
	}
	
	public void counter() {
		curIndex++;
	}
	
	public int getCurZoom() {
		return this.curZoomIdx;
	}
	
	public void setCurZoom(int curZoom) {
		this.curZoomIdx = curZoom;
	}
	
	public String getUrl() {
		return String.format(url, new Random().nextInt(10));
	}
	
	public String getRequestUrl(TileCoord tileCoord) {
		String tempUrl = this.getUrl();
		String x = tileCoord.getX() + "", y = tileCoord.getY() + "";
		if (tileCoord.getX() < 0) {
			x = "M" + Math.abs(tileCoord.getX());
		}
		if (tileCoord.getY() < 0) {
			y = "M" + Math.abs(tileCoord.getY());
		}
		x = x.substring(0, x.indexOf("."));
		y = y.substring(0, y.indexOf("."));
		tempUrl = tempUrl.replace("{z}", tileCoord.getZoom() + "");
		tempUrl = tempUrl.replace("{x}", x);
		tempUrl = tempUrl.replace("{y}", y);
		return tempUrl;
	}
	
	public TileCoord getNextTileCoord() {
		List<Extent> fullTileRange = tileGrid.getTileRanges();
		synchronized (BaiduSourceProvider.class) {
			if(this.curZoomIdx >= fullTileRange.size()) {
				return null;
			}
			Extent extent = fullTileRange.get(this.curZoomIdx);
			double minX = extent.getMinX();
			double minY = extent.getMinY();
			int index = this.curIndex - this.getTileCoorded();
			double indexCount = this.getTileCoordCount(this.curZoomIdx);
			if(index + 1 > indexCount) {
				this.curZoomIdx ++;
				return getNextTileCoord();
			}
			int y = (int) (extent.getMaxY() - minY + 1);
			int yy = index % y;
			int xx = index >= y ? index / y : 0;
			TileCoord result = new TileCoord(this.curIndex, this.offsetZoom + this.curZoomIdx, minX + xx, minY + yy);
			this.counter();
			return result;
		}
	}
	
	private int getTileCoorded() {
		if(this.curZoomIdx == 0) {
			return 0;
		}
		int result = 0;
		for(int i = 0; i < this.curZoomIdx; i++) {
			result += this.getTileCoordCount(i);
		}
		return result;
	}
	
	private int getTileCoordCount(int zoom) {
		List<Extent> fullTileRange = tileGrid.getTileRanges();
		Extent extent = fullTileRange.get(zoom);
		double minX = extent.getMinX();
		double minY = extent.getMinY();
		if(minX == extent.getMaxX() && minY == extent.getMaxY()) {
			return 1;
		}
		double result = (extent.getMaxX() == minX ? 1 : extent.getMaxX() - minX + 1) * (extent.getMaxY() == minY ? 1 : extent.getMaxY() - minY + 1);
		return (int) result ;
	}
	
	public List<TileCoord> enumerateTileRange(TileCoord beginTile) {
		List<TileCoord> list = new ArrayList<>();
//		Map<Integer, List<TileCoord>> map = new HashMap<>();
		List<Extent> fullTileRange = tileGrid.getTileRanges();

		int minZoom = 0, index = 0;
		double minX = fullTileRange.get(minZoom).getMinX();
		double minY = fullTileRange.get(minZoom).getMinY();
		if (beginTile != null) {
			minZoom = beginTile.getZoom();
			minX = beginTile.getX();
			minY = beginTile.getY();
		}
		for (double x = minX; x <= fullTileRange.get(minZoom).getMaxX(); ++x) {
			for (double y = minY; y <= fullTileRange.get(minZoom).getMaxY(); ++y) {
				++index;
				TileCoord tile = new TileCoord(index, minZoom, x, y); //
				list.add(tile);
			}
		}
//		map.put(minZoom, list);

		for (int z = minZoom + 1; z < fullTileRange.size(); z++) {
//			list = new ArrayList<>();
			for (double x = fullTileRange.get(z).getMinX(); x <= fullTileRange.get(z).getMaxX(); ++x) {
				for (double y = fullTileRange.get(z).getMinY(); y <= fullTileRange.get(z).getMaxY(); ++y) {
					++index;
					TileCoord tile = new TileCoord(index, z, x, y);
					list.add(tile);
				}
			}
//			map.put(z, list);
		}
		return list;
	}
}
